﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Linq;
using System.Linq.Expressions;

namespace P3SS.Settings
{
	/// <summary>
	/// The settings that the server relies on
	/// </summary>
	public class ServiceSettings
	{
		#region Constants
		/// <summary>
		/// Absolute location of the settings file
		/// </summary>
		private static readonly string SETTINGS_FILE = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\P3SS\\p3ss.config";
		/// <summary>
		/// Absolute location of the settings file
		/// </summary>
		private static readonly string UIDL_FILE = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\P3SS\\uidls.xml";
		/// <summary>
		/// The number of milliseconds in a minute
		/// </summary>
		public const int MILLISECONDS_PER_MINUTE = 1000 * 60;
		#endregion
		#region Constructors
		/// <summary>
		/// Default constructor
		/// </summary>
		public ServiceSettings()
		{
			Accounts = new List<Account>();
			DefaultAccount = new Account();
			ShowDebugMessages = false;
			MinutesBetweenChecks = 5;
		}
		#endregion
		#region Properties
		/// <summary>
		/// List of accounts (linked POP3 and SMTP accounts)
		/// </summary>
		public List<Account> Accounts { get; set; }

		/// <summary>
		/// Show debug messages in Event Log?
		/// </summary>
		public bool ShowDebugMessages { get; set; }

		/// <summary>
		/// Number of minutes between checking for new email items
		/// </summary>
		public int MinutesBetweenChecks { get; set; }

		/// <summary>
		/// Default settings for an account
		/// </summary>
		public Account DefaultAccount { get; set; }
		#endregion
		#region Public Methods
		/// <summary>
		/// Saves the Unique IDs collected for the POP3 Engines to a file
		/// </summary>
		public void SaveUIDLs()
		{
			XmlSerializer uidlSerializer = new XmlSerializer(typeof(UIDLContainerItem[]));
			UIDLContainerItem[] uidls = (from t in Accounts
										 select new UIDLContainerItem() { UIDLs = t.Pop3Account.CollectedUniqueIDs.ToArray(), POP3Server = t.Pop3Account.ToString() }).ToArray();

			try
			{
				FileInfo uidlFileInfo = new FileInfo(UIDL_FILE);
				CreateFolder(uidlFileInfo.Directory);
				if (uidlFileInfo.Exists)
					uidlFileInfo.Delete();

				FileStream uidlFile = new FileStream(UIDL_FILE, FileMode.Create, FileAccess.Write);
				uidlSerializer.Serialize(uidlFile, uidls);
				uidlFile.Flush();
				uidlFile.Close();
			}
			catch
			{
			}
		}
		
		/// <summary>
		/// Loads the Unique IDs collected from a file
		/// </summary>
		public void LoadUIDLs()
		{
			UIDLContainerItem[] newUidls = null;
			FileStream uidlFile = null;

			try
			{
				XmlSerializer uidlSerializer = new XmlSerializer(typeof(UIDLContainerItem[]));

				uidlFile = new FileStream(UIDL_FILE, FileMode.Open, FileAccess.Read);
				newUidls = (UIDLContainerItem[])uidlSerializer.Deserialize(uidlFile);
				uidlFile.Close();
			}
			catch
			{
				newUidls = new UIDLContainerItem[0];

				try
				{
					uidlFile.Close();
				}
				catch { }

				FileInfo uidlFileInfo = new FileInfo(UIDL_FILE);
				if (uidlFileInfo.Exists)
					uidlFileInfo.Delete();
			}

			foreach (UIDLContainerItem theseUidls in newUidls)
			{
				var thisAccount = from t in Accounts
								  where t.Pop3Account.ToString() == theseUidls.POP3Server
								  select t;

				if (thisAccount.Count() > 0)
				{
					thisAccount.First().Pop3Account.CollectedUniqueIDs = new List<string>(theseUidls.UIDLs);
				}
			}
		}

		/// <summary>
		/// Checks if these settings are the same as another set of settings
		/// </summary>
		/// <param name="obj">Other settings to compare to this</param>
		/// <returns>True if all of the accounts are the same, otherwise false</returns>
		public override bool Equals(object obj)
		{
			bool isEqual = false;

			if (obj is ServiceSettings)
			{
				ServiceSettings otherSettings = (ServiceSettings)obj;

				if ((DefaultAccount.Equals(otherSettings.DefaultAccount)) && (otherSettings.Accounts.Count == Accounts.Count) && (ShowDebugMessages == otherSettings.ShowDebugMessages) && (MinutesBetweenChecks == otherSettings.MinutesBetweenChecks))
				{
					bool accountsSame = true;
					int counter = 0;
					List<Account> accountsToCheck = new List<Account>(otherSettings.Accounts);

					while ((counter < Accounts.Count) && (accountsSame))
					{
						bool foundAccount = false;
						int subcounter = 0;
						while ((subcounter < accountsToCheck.Count) && (!foundAccount))
						{
							if (Accounts[counter].Equals(accountsToCheck[subcounter]))
							{
								foundAccount = true;
								accountsToCheck.RemoveAt(subcounter);
							}
							subcounter++;
						}

						if (!foundAccount)
						{
							accountsSame = false;
						}

						counter++;
					}

					if (accountsSame)
					{
						isEqual = true;
					}
				}
			}

			return isEqual;
		}

		/// <summary>
		/// Creates a unique ID for this object
		/// </summary>
		/// <returns></returns>
		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
		#endregion
		#region Static Methods
		/// <summary>
		/// Loads settings from file
		/// </summary>
		/// <returns>Loaded settings if successfully read, otherwise a new ServiceSettings object</returns>
		public static ServiceSettings LoadSettings()
		{
			ServiceSettings newSettings = null;
			FileStream settingsFile = null;

			try
			{
				XmlSerializer settingsSerializer = new XmlSerializer(typeof(ServiceSettings));

				settingsFile = new FileStream(SETTINGS_FILE, FileMode.Open, FileAccess.Read);
				newSettings = (ServiceSettings)settingsSerializer.Deserialize(settingsFile);
				settingsFile.Close();
			}
			catch
			{
				newSettings = new ServiceSettings();

				try
				{
					settingsFile.Close();
				}
				catch { }

				FileInfo settingsFileInfo = new FileInfo(SETTINGS_FILE);
				if (settingsFileInfo.Exists)
					settingsFileInfo.Delete();
			}

			return newSettings;
		}

		/// <summary>
		/// Saves settings to file
		/// </summary>
		/// <param name="inSettings">Settings to save</param>
		public static void SaveSettings(ServiceSettings inSettings)
		{
			XmlSerializer settingsSerializer = new XmlSerializer(typeof(ServiceSettings));

			try
			{
				FileInfo settingsFileInfo = new FileInfo(SETTINGS_FILE);
				CreateFolder(settingsFileInfo.Directory);
				if (settingsFileInfo.Exists)
					settingsFileInfo.Delete();

				FileStream settingsFile = new FileStream(SETTINGS_FILE, FileMode.Create, FileAccess.Write);
				settingsSerializer.Serialize(settingsFile, inSettings);
				settingsFile.Flush();
				settingsFile.Close();
			}
			catch
			{
			}
		}

	

		/// <summary>
		/// Creates a folder and any parents along its path that don't exist
		/// </summary>
		/// <param name="inDirectory">Directory to create</param>
		private static void CreateFolder(DirectoryInfo inDirectory)
		{
			if (!inDirectory.Exists)
			{
				CreateFolder(inDirectory.Parent);
				inDirectory.Create();
			}
		}
		#endregion
	}
}
